package com.alex.common.persistent;

import java.beans.PropertyDescriptor;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.stereotype.Service;

import com.alex.common.cache.ICacheable;
import com.alex.common.tools.DateUtils;

@Service
public class CommonService {

	private static final String CLAZ = "class";

	private CommonDao dao = CommonDao.getInstance();

	private CommonService() {
	}

	private static final CommonService me = new CommonService();

	/**
	 * @deprecated using spring Autowired
	 * @return
	 */
	public static CommonService getInstance() {
		return me;
	}

	/**
	 * 
	 * @param pClaz
	 * @param conditions
	 *            could be null
	 * @param parameters
	 *            could be null
	 * @param first
	 * @param max
	 *            0 0,0 is all
	 * @return
	 */
	public List<?> queryList(Class<?> pClaz, String conditions,
			List<?> parameters, int first, int max) {
		return dao.query(pClaz, conditions, parameters, first, max);
	}

	public Collection<?> queryAllCached(final Class<? extends ICacheable> pClaz) {
		return dao.query(pClaz);
	}

	/**
	 * Only use for CommDataController
	 * 
	 * @param pClaz
	 * @param conditions
	 * @param parameters
	 * @param first
	 * @param max
	 *            0 0,0 is all
	 * @return
	 */
	public List<Map<String, Object>> queryListMap(Class<?> pClaz,
			String conditions, List<?> parameters, int first, int max) {
		List<?> list = dao.query(pClaz, conditions, parameters, first, max);

		String[] propNames = getPropNames(new BeanWrapperImpl(pClaz));

		boolean hasClaz = false;

		Map<String, Object> keyMap = new LinkedHashMap<String, Object>();
		for (String propName : propNames) {
			keyMap.put(propName, null);
			if (CLAZ.equals(propName)) {
				hasClaz = true;
			}
		}
		if (!hasClaz) {
			keyMap.put(CLAZ, null);
		}

		List<Map<String, Object>> rt = new ArrayList<Map<String, Object>>();
		rt.add(keyMap);

		for (Object object : list) {
			BeanWrapper bean = new BeanWrapperImpl(object);

			Map<String, Object> value = new LinkedHashMap<String, Object>();
			for (String propName : propNames) {
				Object str = bean.getPropertyValue(propName);
				// register Text transation
				// if (str instanceof Text)
				// str = ((Text) str).getValue();
				// if (str instanceof Date)
				// str = DateUtils.getDateSecondFormat((Date) str);
				value.put(propName, str);
			}
			if (!hasClaz) {
				value.put(CLAZ, pClaz.getName());
			}
			rt.add(value);
		}

		return rt;
	}

	public Object find(Class<? extends ICacheable> pClaz, String biz_key) {
		return dao.find(pClaz, biz_key);
	}

	public void insert(Object dto) {
		dao.insert(dto);
	}

	public void insert(Map<String, Object> valueMap)
			throws ClassNotFoundException {
		Object claz = valueMap.remove(CLAZ);
		if (claz.getClass().isArray()) {
			claz = ((String[]) claz)[0];
		}
		BeanWrapper bean = new BeanWrapperImpl(Class.forName((String) claz));

		bean.registerCustomEditor(Date.class, new CommonDateEditor(
				new SimpleDateFormat(DateUtils.DEFAULT_FORMAT), true));

		bean.setPropertyValues(valueMap);
		dao.insert(bean.getWrappedInstance());
	}

	public void update(Map<String, Object> valueMap, Long id)
			throws ClassNotFoundException {
		Object claz = valueMap.remove(CLAZ);
		if (claz.getClass().isArray()) {
			claz = ((String[]) claz)[0];
		}
		dao.update(valueMap, (String) claz, id);
	}

	public void delete(Class<?> pClaz, Long id) {
		dao.delete(pClaz, id);
	}

	private String[] getPropNames(BeanWrapper bean) {
		PropertyDescriptor[] propDescs = bean.getPropertyDescriptors();
		String[] propNames = new String[propDescs.length];
		int i = 0;
		for (PropertyDescriptor propertyDescriptor : propDescs) {
			propNames[i++] = propertyDescriptor.getName();
		}
		return propNames;
	}

}
